gusucode.com > VC++ EMF图片浏览器(可读emf、wmf、emz、wmz、png……等)-源码程序 > VC++ EMF图片浏览器(可读emf、wmf、emz、wmz、png……等)-源码程序/code/Src/Client/scemflib/SCEMFDoc.cpp
//Download by http://www.NewXing.com /* * This file is part of the EMFexplorer projet. * Copyright (C) 2004 Smith Charles. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * * Extension: for commercial use, apply the Equity Public License, which * adds to the normal terms of the GLPL a condition of donation to the author. * If you are interested in support for this source code, * contact Smith Charles <smith.charles@free.fr> for more information. */ #include "stdafx.h" #include "SCEMFDoc.h" #include "SCGenInclude.h" #include SC_INC_COMMON(kSCProdDefs.h) #include SC_INC_WINLIB(SCWinFile.h) #include SC_INC_ERRLIB(wErr.h) #include SC_INC_SHARED(SCZipFile.h) #include SC_INC_WINLIB(SCRegistry.h) #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define SC_EMFX_TMPFONT_EXT _T(".eft") #define SC_EMFX_TMPFRES_EXT _T(".efr") #define SC_EMFX_TEMPSUBDIR SC_PRODUCTNAME #define SC_EMFX_CLIP_FNAME _T("Clipboard") SCEMFDoc::SCEMFDoc(): m_uiNbFiles(0), m_bDocModified(FALSE), m_bForgedName(FALSE) { } SCEMFDoc::~SCEMFDoc() { SCCleanup(TRUE); SCDeleteLockedFontFiles(TRUE); } void SCEMFDoc::SCCleanup(BOOL bClosing /*=FALSE*/) { UINT uiNbPages = m_uiNbFiles; m_uiNbFiles = 0; // Won't serve pages after this, as we are deleting them // Proceed with clean up for (UINT i=0; (i<uiNbPages); i++) { delete m_vDocPages[i]; } m_vDocPages.clear(); SCUnInstallFonts(); m_strUniDocName.Empty(); m_bForgedName = FALSE; } void SCEMFDoc::SCSetPageURL(UINT uiPage, LPCTSTR lpszURL) { ASSERT(uiPage<m_uiNbFiles); if (uiPage<m_uiNbFiles) m_vDocPages[uiPage]->m_strCreditURL = lpszURL; } void SCEMFDoc::SCSetPageCredit(UINT uiPage, LPCTSTR lpszCredit) { ASSERT(uiPage<m_uiNbFiles); if (uiPage<m_uiNbFiles) m_vDocPages[uiPage]->m_strCredit = lpszCredit; } void SCEMFDoc::SCSetPageComment(UINT uiPage, LPCTSTR lpszComment) { ASSERT(uiPage<m_uiNbFiles); if (uiPage<m_uiNbFiles) m_vDocPages[uiPage]->m_strComment = lpszComment; } PSCEMFDocPage SCEMFDoc::SCGetDocPage(UINT uiPage, BOOL bGetCopy/*=FALSE*/) { ASSERT(uiPage<m_uiNbFiles); PSCEMFDocPage pDocPage = NULL; if (uiPage<m_uiNbFiles) { ASSERT(m_vDocPages[uiPage]); if (bGetCopy) { pDocPage = new SCEMFDocPage(this); pDocPage->SCCopyFrom(*m_vDocPages[uiPage]); } else pDocPage = m_vDocPages[uiPage]; } return pDocPage; } HENHMETAFILE SCEMFDoc::SCUnlockEMF(UINT uiPage, PSCEMFDocPage pShare/*=NULL*/) { ASSERT(uiPage<m_uiNbFiles); PSCEMFDocPage pDocPage = m_vDocPages[uiPage]; ASSERT(pDocPage); HENHMETAFILE hMemEMF = pDocPage->SCUnlockEMF(); if (pShare) pShare->m_hEMF = hMemEMF; return hMemEMF; } void SCEMFDoc::SCForgeDocName(LPCTSTR lpszFname) {// forge a doc name m_strUniDocName = lpszFname; int iPos = m_strUniDocName.ReverseFind(_T('.')); if (iPos!=-1) m_strUniDocName = m_strUniDocName.Left(iPos); m_strUniDocName += SC_DOC_EXTENSION; m_bForgedName = TRUE; } void SCEMFDoc::SCRemovePage(UINT uiPage) { ASSERT(uiPage<m_uiNbFiles); delete m_vDocPages[uiPage]; m_vDocPages.erase(m_vDocPages.begin() + uiPage); m_uiNbFiles--; if ((0==m_uiNbFiles) && m_bForgedName) SCCleanup(); m_bDocModified = TRUE; } BOOL SCEMFDoc::SCReflow(DOCPAGEVECTOR& rvectReflow, INTVECTOR& rvectDescrip, LPCTSTR lpszDocDir, int iDlftCrdPage) { UINT uiNbElems = rvectReflow.size(); ASSERT(rvectDescrip.size()==uiNbElems); ASSERT(lpszDocDir); ASSERT(iDlftCrdPage<(int)uiNbElems); { CString strOldDocDir; TCHAR szDrive[_MAX_DRIVE]; TCHAR szDir[_MAX_DIR]; TCHAR szFname[_MAX_FNAME]; TCHAR szExt[_MAX_EXT]; SCSplitPath(m_strUniDocName, szDrive, szDir, szFname, szExt); strOldDocDir.Format(_T("%s%s"), szDrive, szDir); if (0!=strOldDocDir.CompareNoCase(lpszDocDir)) m_strUniDocName.Format(_T("%s%s%s"), lpszDocDir, szFname, szExt); } PSCEMFDocPage pEPage; // Detach old EMFs for (UINT uiPage=0; (uiPage<uiNbElems); uiPage++) { int iIdx = rvectDescrip[uiPage]; if (iIdx>=0) { ASSERT(iIdx<m_uiNbFiles); pEPage=m_vDocPages[iIdx]; ASSERT(pEPage); if (pEPage) pEPage->SCDetachEMF(); } } // Delete old objects for (uiPage=0; (uiPage<m_uiNbFiles); uiPage++) { if (pEPage=m_vDocPages[uiPage]) delete pEPage; } m_vDocPages.clear(); // Copy new objects m_vDocPages.resize(uiNbElems); m_vDocPages.assign(rvectReflow.begin(), rvectReflow.end()); rvectReflow.clear(); m_uiNbFiles = m_vDocPages.size(); if (iDlftCrdPage<0) { m_Properties.strCreditURL.Empty(); m_Properties.strCredit.Empty(); } else { pEPage=m_vDocPages[iDlftCrdPage]; m_Properties.strCreditURL = pEPage->m_strCreditURL; m_Properties.strCredit = pEPage->m_strCredit; } m_bDocModified = TRUE; return TRUE; } void SCEMFDoc::SCBeginAddFiles(UINT uiNbFiles, LPCTSTR lpszFName/*=NULL*/) { SCCleanup(); if (lpszFName) m_strUniDocName = lpszFName; // pages bank if (uiNbFiles) { m_vDocPages.resize(uiNbFiles); m_uiNbFiles = uiNbFiles; m_vDocPages.assign(m_uiNbFiles, NULL); } } void SCEMFDoc::SCEndAddFiles() { SCInstallFonts(); } void SCEMFDoc::SCSetDocDir(LPCTSTR lpszDocDir) { DWORD dwLen = (lpszDocDir) ? _tcslen(lpszDocDir) : 0; ASSERT(dwLen); ASSERT(!m_strUniDocName.IsEmpty()); CString strOldDocDir = SCMakeupDocDir(m_strUniDocName); ASSERT(strOldDocDir.IsEmpty()|| strOldDocDir.CompareNoCase(lpszDocDir)==0); if (strOldDocDir.IsEmpty()) { ASSERT(m_bForgedName); if (lpszDocDir[dwLen-1]!=_T('\\')) m_strUniDocName.Insert(0, _T('\\')); m_strUniDocName.Insert(0, lpszDocDir); } SCInstallFonts(); } BOOL SCEMFDoc::SCAddFile(LPCTSTR lpszFname, UINT uiIdx, BOOL bCopy/*=TRUE*/, BOOL bDelayed/*=FALSE*/) { ASSERT(uiIdx<m_uiNbFiles); if (uiIdx>=m_uiNbFiles) return FALSE; BOOL bError = FALSE; // check filetype UINT uiFyleType = SC_FSTATE_DELAYED; if (!bDelayed) { uiFyleType = SCGetFileType(lpszFname, FALSE); switch (uiFyleType & SC_FTYPE_MASK) { case SC_FTYPE_EMF: case SC_FTYPE_WMF: case SC_FTYPE_EMZ: case SC_FTYPE_WMZ: case SC_FTYPE_IMG: case SC_FTYPE_TXT: break; case SC_FTYPE_UKN: default: bError = TRUE; // delay loading, so that user can use reflow to replace the file uiFyleType = SC_FSTATE_DELAYED; } } SCEMFDocPage* pDocPage = new SCEMFDocPage(this); m_vDocPages[uiIdx] = pDocPage; // set information for delayed loading pDocPage->m_uiType = uiFyleType; pDocPage->m_strPath = lpszFname; if (!bError && m_strUniDocName.IsEmpty()) SCForgeDocName(lpszFname); return TRUE; } BOOL SCEMFDoc::SCLoadRTFPages(LPCTSTR lpszFname, BOOL bPaste/*=FALSE*/, BOOL bRTF/*=TRUE*/) { HEMFVECTOR vectHandles; UINT uiNbPages = SCConvertRTFtoEMF(lpszFname, vectHandles, bRTF); if (0==uiNbPages) return FALSE; UINT uiStartIdx=0; if (bPaste) { uiStartIdx = m_uiNbFiles; m_uiNbFiles += uiNbPages; m_vDocPages.resize(m_uiNbFiles); } else SCBeginAddFiles(uiNbPages); // EMFs are just in memory, like a paste: don't forge unidoc name CString strPrefix = SCFNameExtFromPath(lpszFname); int iPos = strPrefix.ReverseFind(_T('.')); if (iPos!=-1) strPrefix.SetAt(iPos, _T('_')); if (!m_strUniDocName.IsEmpty()) { CString strDir; TCHAR drive[_MAX_DRIVE]; // drive of the playlist TCHAR dir[_MAX_DIR]; // dir of the playlist _tsplitpath(LPCTSTR(m_strUniDocName), drive, dir, NULL, NULL); strDir.Format(_T("%s%s"), drive, dir); strPrefix = strDir + strPrefix; } CString strFname; for (UINT uiIdx=uiStartIdx; (uiIdx<m_uiNbFiles); uiIdx++) { SCEMFDocPage* pDocPage = new SCEMFDocPage(this); m_vDocPages[uiIdx] = pDocPage; strFname.Format(_T("%s_p%d.emf"), strPrefix, (uiIdx - uiStartIdx)+1); pDocPage->m_bDirty = TRUE; pDocPage->SCAttachEMF(vectHandles[uiIdx - uiStartIdx], strFname, SC_FILETYPE_EMFONLY); } if (!bPaste) SCEndAddFiles(); m_bDocModified = TRUE; // pages are just in memory return TRUE; } BOOL SCEMFDoc::SCGrowBank(int iNbPages) { m_uiNbFiles += iNbPages; m_vDocPages.resize(m_uiNbFiles); return TRUE; } BOOL SCEMFDoc::SCPasteEMFPages(HEMFVECTOR& rVector) { int iNbPages = rVector.size(); if (0==iNbPages) return FALSE; UINT uiNewNbPages = m_uiNbFiles + iNbPages; m_vDocPages.resize(uiNewNbPages); // Folder of the new files CString strDir; if (!m_strUniDocName.IsEmpty()) { TCHAR drive[_MAX_DRIVE]; // drive of the playlist TCHAR dir[_MAX_DIR]; // dir of the playlist _tsplitpath(LPCTSTR(m_strUniDocName), drive, dir, NULL, NULL); strDir.Format(_T("%s%s"), drive, dir); } // Name and paste the files static UINT s_uiClipNum = 0; CString strClipFname; for (UINT uiIdx=m_uiNbFiles; (uiIdx<uiNewNbPages); uiIdx++) { SCEMFDocPage* pDocPage = new SCEMFDocPage(this); m_vDocPages[uiIdx] = pDocPage; strClipFname.Format(_T("%s%s%d.emf"), strDir, SC_EMFX_CLIP_FNAME, ++s_uiClipNum); pDocPage->m_bDirty = TRUE; pDocPage->SCAttachEMF(rVector[uiIdx - m_uiNbFiles], strClipFname, SC_FILETYPE_EMFONLY); } m_uiNbFiles = uiNewNbPages; m_bDocModified = TRUE; // some pages are just in memory return TRUE; } HENHMETAFILE SCEMFDoc::SCGetPageEMF(UINT uiPage) { ASSERT(uiPage<m_uiNbFiles); if (uiPage>=m_uiNbFiles) return NULL; return m_vDocPages[uiPage]->SCGetPageEMF(); } void SCEMFDoc::SCResizeAllPages() { m_Properties.bSizeAllPages = !m_Properties.bSizeAllPages; if (!m_Properties.rectDocument.IsRectEmpty()) { if (m_Properties.bSizeAllPages) {// apply for (UINT uiPage=0; (uiPage<m_uiNbFiles); uiPage++) { PSCEMFDocPage pDocPage = m_vDocPages[uiPage]; ASSERT(pDocPage); pDocPage->m_rectSize = m_Properties.rectDocument; } } else {// restore for (UINT uiPage=0; (uiPage<m_uiNbFiles); uiPage++) { PSCEMFDocPage pDocPage = m_vDocPages[uiPage]; ASSERT(pDocPage); pDocPage->SCRecomputeElemsRect(); if (pDocPage->m_bInflate) pDocPage->m_rectSize.InflateRect(pDocPage->m_rectInflate); } } return; } ASSERT(m_Properties.bSizeAllPages); int iMinX = INT_MAX; int iMinY = INT_MAX; int iMaxX = INT_MIN; int iMaxY = INT_MIN; for (UINT uiPage=0; (uiPage<m_uiNbFiles); uiPage++) { PSCEMFDocPage pDocPage = m_vDocPages[uiPage]; ASSERT(pDocPage); HENHMETAFILE hEMF = pDocPage->SCGetPageEMF(); if (hEMF) { CRect& ElemsRect = pDocPage->m_rectSize; // deflate CRect& rectI = pDocPage->m_rectInflate; ElemsRect.InflateRect(-rectI.left, -rectI.top, -rectI.right, -rectI.bottom); // if (ElemsRect.left<iMinX) iMinX = ElemsRect.left; if (ElemsRect.top<iMinY) iMinY = ElemsRect.top; if (ElemsRect.right>iMaxX) iMaxX = ElemsRect.right; if (ElemsRect.bottom>iMaxY) iMaxY = ElemsRect.bottom; } } ASSERT(iMinX != INT_MAX); ASSERT(iMinY != INT_MAX); ASSERT(iMaxX != INT_MIN); ASSERT(iMaxY != INT_MIN); for (uiPage=0; (uiPage<m_uiNbFiles); uiPage++) { m_vDocPages[uiPage]->m_rectSize.SetRect(iMinX, iMinY, iMaxX, iMaxY); } m_Properties.rectDocument.SetRect(iMinX, iMinY, iMaxX, iMaxY); } void SCEMFDoc::SCInflateElemsRect(UINT uiPage, int iLeft, int iTop, int iRight, int iBottom) { ASSERT(uiPage<m_uiNbFiles); if (uiPage>=m_uiNbFiles) return; m_vDocPages[uiPage]->SCInflateElemsRect(iLeft, iTop, iRight, iBottom); } /// /// Install all fonts found in the 'Fonts' subdirectory (of the document's directory) /// void SCEMFDoc::SCInstallFonts() { SCDeleteLockedFontFiles(); // delayed clean up // For now, just install what is found in the Fonts subdirectory if any if (m_strUniDocName.IsEmpty()) return; TCHAR drive[_MAX_DRIVE]; // drive of the playlist TCHAR dir[_MAX_DIR]; // dir of the playlist _tsplitpath(LPCTSTR(m_strUniDocName), drive, dir, NULL, NULL); // Look for TT fonts CString strFile; strFile.Format(_T("%s%s%s"), drive, dir, _T("Fonts\\*.*")); CFileFind finder; BOOL bFound = finder.FindFile((LPCTSTR)strFile); BOOL bTemp = FALSE; CString strTempPath; if (bFound) { bTemp = (!SCIsWriteableMedia(m_strUniDocName)); if (bTemp) {// create temp directory if (!::SCCreateTempDir(strTempPath, SC_EMFX_TEMPSUBDIR)) { ASSERT(0); finder.Close(); return; } } } while (bFound) { bFound = finder.FindNextFile(); if (!finder.IsDirectory()) { CString strFilePath = finder.GetFilePath(); if (!SCIsTrueTypeFontFile(strFilePath)) continue; // TODO: Check that font is not already installed // if (m_pSysFontsHolder && m_pSysFontsHolder->SCIsFontInstalled(strFilePath)) // continue; if (bTemp) {// copy to temp directory TCHAR szFname[_MAX_FNAME]; SCSplitPath((LPTSTR)LPCTSTR(strFilePath), NULL, NULL, szFname, NULL); CString strFilename; strFilename.Format(_T("%s%s%s"), strTempPath, szFname, SC_EMFX_TMPFONT_EXT); #ifdef _DEBUG ASSERT(!SCExistFile(strFilename)); #endif BOOL bOk = CopyFile(strFilePath, strFilename, TRUE); ASSERT(bOk); strFilePath = strFilename; } SCInstallFontFile(strFilePath, bTemp); } } finder.Close(); #ifdef _DEBUG int iCount = m_FontRes.GetCount(); #endif } /// /// Uninstall fonts, and delete temporary files. /// void SCEMFDoc::SCUnInstallFonts() { CString strTempPath; ::SCGetFullTempDirName(strTempPath, SC_EMFX_TEMPSUBDIR); BOOL bTempCheck = FALSE; BOOL bTempFiles = FALSE; POSITION pos = m_FontRes.GetHeadPosition(); CString strFilename; BOOL bOK; while(pos) { strFilename = m_FontRes.GetNext(pos); ASSERT(!strFilename.IsEmpty()); bOK = RemoveFontResource(strFilename); ASSERT(bOK); if (!bOK) continue; // delete the scalable resource file bOK = DeleteFile(strFilename); ASSERT(bOK); if (!bTempCheck) {// check if TT files are in temp directory TCHAR szDrive[SC_MAX_UNC_DRIVE]; TCHAR szDir[_MAX_DIR]; SCSplitPath(strFilename, szDrive, szDir, NULL, NULL); CString strFilesDir; strFilesDir.Format(_T("%s%s"), szDrive, szDir); if (0==strTempPath.Compare(strFilesDir)) { int iPos = strFilename.ReverseFind(_T('.')); if (iPos>0) { CString strTTFName = strFilename.Left(iPos) + SC_EMFX_TMPFONT_EXT; bTempFiles = SCExistFile(strTTFName); } } bTempCheck = TRUE; } // delete temporary font file if (bTempFiles) { int iPos = strFilename.ReverseFind(_T('.')); if (iPos>0) { CString strTTFName = strFilename.Left(iPos) + SC_EMFX_TMPFONT_EXT; bOK = SCRemoveFileAttributes(strTTFName, FILE_ATTRIBUTE_READONLY); ASSERT(bOK); bOK = DeleteFile(strTTFName); // Deceptively, Windows locks some fonts AFTER they have passed through // metafile playing, though they are OUR private fonts. // TODO: find reason. if (!bOK) m_LockedFontFiles.AddTail(strTTFName); // font to delete later } } } m_FontRes.RemoveAll(); } /// /// Delete fonts that were locked in a previous attempt to delete them. /// void SCEMFDoc::SCDeleteLockedFontFiles(BOOL bClosing/*=FALSE*/) { POSITION pos = m_LockedFontFiles.GetHeadPosition(); CString strFilename; if (bClosing) {// Just delete the files. They should be deleteable at this point. while(pos) { strFilename = m_LockedFontFiles.GetNext(pos); ASSERT(!strFilename.IsEmpty()); BOOL bOK = SCRemoveFileAttributes(strFilename, FILE_ATTRIBUTE_READONLY); ASSERT(bOK); bOK = DeleteFile(strFilename); ASSERT(bOK); } return; } // Attemp to delete. Keep those files that are still locked. CStringList RemainList; while(pos) { strFilename = m_LockedFontFiles.GetNext(pos); ASSERT(!strFilename.IsEmpty()); if (!DeleteFile(strFilename)) RemainList.AddTail(strFilename); } m_LockedFontFiles.RemoveAll(); pos = RemainList.GetHeadPosition(); while(pos) { m_LockedFontFiles.AddTail(RemainList.GetNext(pos)); } } /// /// Install a TrueType read-only embedded font from memory data /// BOOL SCEMFDoc::SCInstallMemoryFont(CString strFaceName, BYTE* lpData, long lDataSize) { // 1. check if its a TrueType // 2. avoid installing fonts on the system (copy their files // into temp directory) CString strTempPath; if (!::SCCreateTempDir(strTempPath, SC_EMFX_TEMPSUBDIR)) { ASSERT(0); return FALSE; } int iPos = strFaceName.ReverseFind(_T('.')); if (-1==iPos) strFaceName += SC_EMFX_TMPFONT_EXT; else strFaceName = strFaceName.Left(iPos) + SC_EMFX_TMPFONT_EXT; CString strFilename = strTempPath + strFaceName; #ifdef _DEBUG ASSERT(!SCExistFile(strFilename)); // it should not exist #endif CFile file; CFileException fe; // create new file, 'Open' won't throw exception if (file.Open(strFilename, CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive, &fe)) { // save the data try { file.Write(lpData, lDataSize); } catch(CFileException* pEx) { pEx->Delete(); ASSERT(0); file.Close(); return FALSE; } file.Close(); } else { ASSERT(0); return FALSE; } // 3. install and store filename return SCInstallFontFile(strFilename, TRUE); } /// /// Install a TrueType read-only embedded font from a file /// BOOL SCEMFDoc::SCInstallFontFile(CString strFilename, BOOL bTemporary) { CString strFontRes; int iPos = strFilename.ReverseFind(_T('.')); if (iPos>0) { strFontRes = strFilename.Left(iPos) + SC_EMFX_TMPFRES_EXT; } else strFontRes = strFilename + SC_EMFX_TMPFRES_EXT; DeleteFile(strFontRes); BOOL bCreated = CreateScalableFontResource( 1, // 0/1=flag for read-only embedded font LPCTSTR(strFontRes), // pointer to filename for font resource LPCTSTR(strFilename), // pointer to filename for scalable font LPCTSTR(NULL) // pointer to path to font file ); DWORD dwError = GetLastError(); //ASSERT(bCreated); // Font file must be TrueType if (!bCreated) { if (bTemporary) DeleteFile(strFilename); return FALSE; } int iInstalled = AddFontResource(strFontRes); ASSERT(iInstalled); if (!iInstalled) { BOOL bOK = RemoveFontResource(strFontRes); ASSERT(bOK); if (bTemporary) DeleteFile(strFilename); return FALSE; } m_FontRes.AddTail(strFontRes); return TRUE; } void SCEMFDoc::SCNewDocument() { SCBeginAddFiles(0); SCEndAddFiles(); } UINT SCEMFDoc::SCOpenDocument(LPCTSTR lpszPathName) { UINT uiFileType = SCEMFDoc::SCGetFileType(lpszPathName); switch(uiFileType & SC_FTYPE_MASK) { case SC_FTYPE_UKN : return uiFileType; case SC_FTYPE_BGP : SCLoadMaster(lpszPathName); break; case SC_FTYPE_EMF: case SC_FTYPE_WMF: case SC_FTYPE_EMZ: case SC_FTYPE_WMZ: case SC_FTYPE_IMG: SCLoadSinglePage(lpszPathName, uiFileType); break; case SC_FTYPE_TXT: if (!SCLoadRTFPages(lpszPathName, FALSE, (SC_SUBTYPE_TXT_RTF==(uiFileType & SC_SUBTYPE_MASK)))) return SC_FTYPE_UKN; break; default: ASSERT(0); } return uiFileType; } BOOL SCEMFDoc::SCInsertFile(LPCTSTR lpszPathName, UINT* puiType/*=NULL*/) { UINT uiFileType = SCEMFDoc::SCGetFileType(lpszPathName); if (puiType) *puiType = uiFileType; BOOL bInserted = FALSE; switch(uiFileType & SC_FTYPE_MASK) { case SC_FTYPE_UKN : return FALSE; case SC_FTYPE_BGP : // Merge isn't supported in this version //return SCLoadMaster(lpszPathName, TRUE); return FALSE; case SC_FTYPE_EMF: case SC_FTYPE_WMF: case SC_FTYPE_EMZ: case SC_FTYPE_WMZ: case SC_FTYPE_IMG: bInserted = SCLoadSinglePage(lpszPathName, uiFileType, TRUE); break; case SC_FTYPE_TXT: bInserted = SCLoadRTFPages(lpszPathName, TRUE, (SC_SUBTYPE_TXT_RTF==(uiFileType & SC_SUBTYPE_MASK))); break; default: ASSERT(0); } if (bInserted) m_bDocModified = TRUE; return bInserted; } /// /// Load the main data format supported by this class (enlist pages) /// BOOL SCEMFDoc::SCLoadMaster(LPCTSTR lpszPathName, BOOL bInsert/*=FALSE*/) { ASSERT(lpszPathName); ASSERT(FALSE==bInsert);// not supported yet // Note: in this version, absolute file names are not supported even if they appear // in the master. So directory information is stripped out. TCHAR szDocDrive[_MAX_DRIVE]; // drive of the playlist TCHAR szDocDir[_MAX_DIR]; // dir of the playlist TCHAR szFname[_MAX_FNAME]; // name of a file TCHAR szExt[_MAX_EXT]; // ext of a file _tsplitpath(lpszPathName, szDocDrive, szDocDir, NULL, NULL); TCHAR szBuff[MAX_PATH]; // Number of files ::GetPrivateProfileString(SC_DOC_GEN_SECTION, SC_DOC_NBFILES_KEY, _T(""), szBuff, MAX_PATH, lpszPathName); TCHAR szTxtBuff[SC_PGCOMMENT_MAXSIZE]; UINT uiNbFiles = _ttoi(szBuff); SCBeginAddFiles(uiNbFiles, lpszPathName); for (UINT nFile=0; (nFile<uiNbFiles); nFile++) { CString strKey; strKey.Format(SC_DOC_FILEKEY_FORMAT, nFile); ::GetPrivateProfileString(SC_DOC_FILES_SECTION, strKey, _T(""), szBuff, MAX_PATH, lpszPathName); _tsplitpath(szBuff, NULL, NULL, szFname, szExt); strKey.Format(_T("%s%s%s%s"), szDocDrive, szDocDir, szFname, szExt); SCAddFile(LPCTSTR(strKey), nFile, TRUE, (nFile>0)); // Page attributes CString strPgSection; strPgSection.Format(SC_DOC_PGSECTION_FORMAT, nFile); ::GetPrivateProfileString(strPgSection, SC_DOC_URL_KEY, _T(""), szTxtBuff, SC_PGCOMMENT_MAXSIZE, lpszPathName); SCSetPageURL(nFile, szTxtBuff); ::GetPrivateProfileString(strPgSection, SC_DOC_CREDIT_KEY, _T(""), szTxtBuff, SC_PGCOMMENT_MAXSIZE, lpszPathName); SCSetPageCredit(nFile, szTxtBuff); ::GetPrivateProfileString(strPgSection, SC_DOC_COMMENT_KEY, _T(""), szTxtBuff, SC_PGCOMMENT_MAXSIZE, lpszPathName); SCSetPageComment(nFile, szTxtBuff); } SCEndAddFiles(); SCLoadSettings(); return TRUE; } // Load a single file (enlist one file) BOOL SCEMFDoc::SCLoadSinglePage(LPCTSTR lpszFname, UINT uiFyleType, BOOL bInsert/*=FALSE*/) { ASSERT(lpszFname); ASSERT(uiFyleType!=SC_FTYPE_UKN); if (bInsert) { UINT uiIdx = m_uiNbFiles; if (!SCGrowBank(1)) return FALSE; SCAddFile(lpszFname, uiIdx, TRUE, TRUE); m_vDocPages[uiIdx]->m_uiType = uiFyleType; } else { SCBeginAddFiles(1); SCAddFile(lpszFname, 0, TRUE, TRUE); m_vDocPages[0]->m_uiType = uiFyleType; SCEndAddFiles(); } return TRUE; } /// /// Save the main data format supported by this class /// BOOL SCEMFDoc::SCSaveDocument(LPCTSTR lpszPathName/*==NULL*/) { CString strPathName = (lpszPathName) ? lpszPathName : m_strUniDocName; ASSERT(!strPathName.IsEmpty()); CString strDocDir = SCMakeupDocDir(strPathName); CString strOldDocDir = SCMakeupDocDir(m_strUniDocName); BOOL bCopyFiles = (strDocDir!=strOldDocDir); // Main section // erase sections ::WritePrivateProfileString(SC_DOC_GEN_SECTION, NULL, NULL, strPathName); ::WritePrivateProfileString(SC_DOC_FILES_SECTION, NULL, NULL, strPathName); // ID ::WritePrivateProfileString(SC_DOC_GEN_SECTION, SC_DOC_FILEID_KEY, SC_DOC_FILEID_VALUE, strPathName); // NbFiles SCWritePrivateProfileInt(SC_DOC_GEN_SECTION, SC_DOC_NBFILES_KEY, m_uiNbFiles, strPathName); // Files BOOL bOneDirty = FALSE; for (UINT uiPage=0; (uiPage<m_uiNbFiles); uiPage++) { PSCEMFDocPage pPage = m_vDocPages[uiPage]; ASSERT(pPage); ASSERT(pPage->m_strPath); CString strPagePath; {// Note: in this version, absolute paths are not supported. Strip them out strPagePath = SCFNameExtFromPath(pPage->m_strPath); ASSERT(!strPagePath.IsEmpty()); } // File EMF if (pPage->m_bDirty) { ASSERT(pPage->m_hEMF); if (pPage->m_hEMF) { CString strSavePath = strDocDir + strPagePath; BOOL bExist = SCExistFile(strSavePath); {// Note: in this version, bDirty means "new page" // Ensure that the file is unique int iPos = strSavePath.ReverseFind(_T('.')); CString strPrefix; CString strExt; if (iPos!=-1) { strPrefix = strSavePath.Left(iPos); // exclude dot strExt = strSavePath.Right(strSavePath.GetLength()-iPos); // include dot } else { ASSERT(0); strPrefix = strSavePath; } for (UINT i=1; (bExist && i<65635); i++) { strSavePath.Format(_T("%s_%d%s"), strPrefix, i, strExt); bExist = SCExistFile(strSavePath); } strPagePath = SCFNameExtFromPath(strSavePath); pPage->m_strPath = strPagePath; } if (SCWriteEMFtoDisk(pPage->m_hEMF, strSavePath)) pPage->m_bDirty = FALSE; } if (pPage->m_bDirty) { bOneDirty = TRUE; continue; } } else if (bCopyFiles) {// copy file CString strSavePath = strDocDir + strPagePath; CString strOldPath = strOldDocDir + strPagePath; // Note: we are overwriting files! if (!::CopyFile(strOldPath, strSavePath, FALSE)) bOneDirty = TRUE; } // File path CString strKey; strKey.Format(SC_DOC_FILEKEY_FORMAT, uiPage); ::WritePrivateProfileString(SC_DOC_FILES_SECTION, strKey, strPagePath, strPathName); // Page attributes CString strPgSection; strPgSection.Format(SC_DOC_PGSECTION_FORMAT, uiPage); ::WritePrivateProfileString(strPgSection, NULL, NULL, strPathName); if (!pPage->m_strCreditURL.IsEmpty()) ::WritePrivateProfileString(strPgSection, SC_DOC_URL_KEY, pPage->m_strCreditURL, strPathName); if (!pPage->m_strCredit.IsEmpty()) ::WritePrivateProfileString(strPgSection, SC_DOC_CREDIT_KEY, pPage->m_strCredit, strPathName); if (!pPage->m_strComment.IsEmpty()) ::WritePrivateProfileString(strPgSection, SC_DOC_COMMENT_KEY, pPage->m_strComment, strPathName); } // Settings SCSaveSettings(strPathName); // Is it clean? m_bDocModified = bOneDirty; m_bForgedName = FALSE; return (!m_bDocModified); } ////////////////////////////////////////////////////////////////////////////////// // Static BOOL SCEMFDoc::SCIsNativeDoc(LPCTSTR lpszFname) { TCHAR szBuff[MAX_PATH]; ::GetPrivateProfileString(SC_DOC_GEN_SECTION, SC_DOC_FILEID_KEY, _T(""), szBuff, MAX_PATH, lpszFname); CString strValue = szBuff; if (!strValue.IsEmpty() && (strValue.CompareNoCase(SC_DOC_FILEID_VALUE)==0)) return TRUE; return FALSE; } CString SCEMFDoc::SCDocFileFromList(CStringList& rLFiles) { POSITION pos = rLFiles.GetHeadPosition(); int iNumFiles = rLFiles.GetCount(); if (1==iNumFiles) {// If one file, do not create playlist file return rLFiles.GetNext(pos); } CString strDocName; WORD nFound = 0; while (pos) { CString strFile = rLFiles.GetNext(pos); if (SCEMFDoc::SCIsNativeDoc(strFile)) {// playlist found in the group if (1==iNumFiles) { strDocName = strFile; break; } // dont mix: ignore playlist continue; } if (strDocName.IsEmpty()) {// Build the doc name (new playlist) and write the number of files strDocName = SCEMFDoc::SCDocNameFromFilename(strFile); if (strDocName.IsEmpty()) break; // could not create temp file // erase sections ::WritePrivateProfileString(SC_DOC_GEN_SECTION, NULL, NULL, strDocName); ::WritePrivateProfileString(SC_DOC_FILES_SECTION, NULL, NULL, strDocName); // ID ::WritePrivateProfileString(SC_DOC_GEN_SECTION, SC_DOC_FILEID_KEY, SC_DOC_FILEID_VALUE, strDocName); } // Store the file path { CString strKey; strKey.Format(SC_DOC_FILEKEY_FORMAT, nFound); ::WritePrivateProfileString(SC_DOC_FILES_SECTION, strKey, strFile, strDocName); nFound++; } } if (!strDocName.IsEmpty()) {// Open the document // Update nb files only if a new playlist was created if (nFound) { ASSERT(nFound<=iNumFiles); CString strValue; strValue.Format(_T("%d"), nFound); ::WritePrivateProfileString(SC_DOC_GEN_SECTION, SC_DOC_NBFILES_KEY, strValue, strDocName); } } return strDocName; } UINT SCEMFDoc::SCGetFileType(LPCTSTR lpszFname, BOOL bShowError/*=TRUE*/) { {// Check special headers (bgp) TCHAR szBuff[MAX_PATH]; ::GetPrivateProfileString(SC_DOC_GEN_SECTION, SC_DOC_FILEID_KEY, _T(""), szBuff, MAX_PATH, lpszFname); CString strValue = szBuff; if (!strValue.IsEmpty() && (strValue.CompareNoCase(SC_DOC_FILEID_VALUE)==0)) return SC_FTYPE_BGP; } UINT uiMode = SetErrorMode(SEM_FAILCRITICALERRORS); // Open the file for reading. HANDLE hFile = CreateFile(lpszFname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); if (hFile == INVALID_HANDLE_VALUE) { SetErrorMode(uiMode); #if 1 // TODO: add string to resource, or don't use it if (bShowError) { DWORD dwError = GetLastError(); CString strMsg; strMsg.Format(_T("Unable to open %s"), lpszFname); SCShowWinError(dwError, SC_PRODUCTNAME, strMsg); } #endif return (SC_FSTATE_NOTFOUND|SC_FTYPE_UKN); } UINT uiType = SC_FTYPE_UKN; // Load file type ENHMETAHEADER hdrBuff; DWORD dwRead; BOOL bResult; // wmf header bResult = ReadFile(hFile, &hdrBuff, 22, &dwRead, NULL); if (bResult && (22==dwRead)) {// file is long enough BYTE* pdwKey = (BYTE*)&hdrBuff; if (*((DWORD*)pdwKey)==WMFMETA_PLACEABLEKEY) uiType = SC_FILETYPE_WMF; // Aldus wmf else if (EMR_HEADER==*((DWORD*)pdwKey)) {// check emf header pdwKey += 22; bResult = ReadFile(hFile, pdwKey, sizeof(ENHMETAHEADER) - 22, &dwRead, NULL) ; if (bResult && (sizeof(ENHMETAHEADER) - 22==dwRead)) {// file is long enough if (ENHMETA_SIGNATURE==hdrBuff.dSignature) { uiType = SC_FILETYPE_EMFONLY; } } } if (SC_FTYPE_UKN==uiType) {// check Windows wmf METAHEADER *pWinWMFHdr = (METAHEADER*)&hdrBuff; if ((1==pWinWMFHdr->mtType || 2==pWinWMFHdr->mtType) && (0x0100==pWinWMFHdr->mtVersion || 0x0300==pWinWMFHdr->mtVersion)) { uiType = SC_FILETYPE_WMF; } } if (SC_FTYPE_UKN==uiType && SCIsGZCandidate((LPBYTE)&hdrBuff, 22)) {// check compressed Windows emf/wmf if (SCUnzipGZFilePart(lpszFname, (LPBYTE)&hdrBuff, sizeof(ENHMETAHEADER))) { pdwKey = (BYTE*)&hdrBuff; if (WMFMETA_PLACEABLEKEY==*((DWORD*)pdwKey)) uiType = SC_FTYPE_WMZ; // Aldus wmf else if (EMR_HEADER==*((DWORD*)pdwKey) && ENHMETA_SIGNATURE==hdrBuff.dSignature) { uiType = SC_FTYPE_EMZ; // emf } else { METAHEADER *pWinWMFHdr = (METAHEADER*)&hdrBuff; if ((1==pWinWMFHdr->mtType || 2==pWinWMFHdr->mtType) && (0x0100==pWinWMFHdr->mtVersion || 0x0300==pWinWMFHdr->mtVersion)) { uiType = SC_FTYPE_WMZ; // Windows wmf } } } } } CloseHandle(hFile); SetErrorMode(uiMode); if (uiType != SC_FTYPE_UKN) return uiType; // images #pragma message( __FILE__ "(1129): TODO: Review image filetype detection") // we would like a detection by content, not by extension uiType = SCFileTypeFromExt(lpszFname, TRUE); return uiType; } CString SCEMFDoc::SCDocNameFromFilename(LPCTSTR lpszFname) { if (!SCIsWriteableMedia(lpszFname)) {// If we can't write on the media, use a temp file TCHAR szPath[MAX_PATH]; TCHAR szBuff[MAX_PATH]; DWORD dwLength = ::GetTempPath(MAX_PATH, szPath); if ((dwLength>0) && (dwLength<MAX_PATH) && ::GetTempFileName(szPath, _T("EMX"), 0, szBuff)) { CString strDocName = szBuff; return strDocName; } return _T(""); } CString strBaseName = lpszFname; int iPos = strBaseName.ReverseFind(_T('.')); if (iPos!=-1) strBaseName = strBaseName.Left(iPos); CString strDocName = strBaseName + SC_DOC_EXTENSION; // Ensure that the file is unique for (UINT i=1; (i<65635); i++) { if (!SCExistFile(strDocName)) return strDocName; strDocName.Format(_T("%s%d%s"), strBaseName, i, SC_DOC_EXTENSION); } return _T(""); }